/**
 * 版权所有(C)，上海勾芒信息科技，2016，所有权利保留。
 * 
 * 项目名：	car-web
 * 文件名：	WxMpDbConfigStorage.java
 * 模块说明：	
 * 修改历史：
 * 2016年11月15日 - Debenson - 创建。
 */
package com.alex.wechat.mp.config;

import java.io.File;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import com.alex.wechat.mp.account.entity.WxAccountEntity;
import com.alex.wechat.mp.account.service.WxAccountServiceI;

import me.chanjar.weixin.common.bean.WxAccessToken;
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
import me.chanjar.weixin.mp.api.WxMpConfigStorage;

/**
 * 基于关系数据库的微信配置。
 * 
 * @author Debenson
 * @since 0.1
 */
public class WxMpDbConfigStorage implements WxMpConfigStorage {

  @Autowired
  private WxAccountServiceI accountService;
  /**
   * 微信通用TOKEN
   */
  @Value("${wx.token}")
  private String token;

  private Lock accessTokenLock = new ReentrantLock();
  private Lock jsapiTicketLock = new ReentrantLock();
  private Lock cardApiTicketLock = new ReentrantLock();

  /**
   * 取得当前公众号。
   * 
   * @return
   */
  protected WxAccountEntity ensureAccount() {
    WxAccountEntity account = WxContext.getWxAccount();
    if (account == null) {
      throw new RuntimeException("没有配置当前公众号");
    }
    return account;
  }

  @Override
  public String getAccessToken() {
    return ensureAccount().getAccesstoken();
  }

  @Override
  public boolean isAccessTokenExpired() {
    final WxAccountEntity account = ensureAccount();
    long expiresTime = (account.getExpiresTime() == null
        || StringUtils.isBlank(account.getAccesstoken())) ? 0 : account.getExpiresTime();
    return System.currentTimeMillis() > expiresTime;
  }

  @Override
  public void expireAccessToken() {
    final WxAccountEntity account = ensureAccount();
    account.setExpiresTime(0L);
    accountService.saveOrUpdate(account);
  }

  @Override
  public void updateAccessToken(WxAccessToken accessToken) {
    updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
  }

  @Override
  public void updateAccessToken(String accessToken, int expiresInSeconds) {
    final WxAccountEntity account = ensureAccount();
    account.setAccesstoken(accessToken);
    if (StringUtils.isBlank(accessToken)) {
      account.setExpiresTime(0L);
    } else {
      account.setExpiresTime(System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l);
    }
    accountService.saveOrUpdate(account);
  }

  @Override
  public String getJsapiTicket() {
    return ensureAccount().getJsapiticket();
  }

  @Override
  public boolean isJsapiTicketExpired() {
    final WxAccountEntity account = ensureAccount();
    long expiresTime = (account.getJsapiTicketExpiresTime() == null
        || StringUtils.isBlank(account.getJsapiticket())) ? 0 : account.getJsapiTicketExpiresTime();
    return System.currentTimeMillis() > expiresTime;
  }

  @Override
  public void expireJsapiTicket() {
    final WxAccountEntity account = ensureAccount();
    account.setJsapiTicketExpiresTime(0L);
    accountService.saveOrUpdate(account);
  }

  @Override
  public void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) {
    final WxAccountEntity account = ensureAccount();
    account.setJsapiticket(jsapiTicket);
    if (StringUtils.isBlank(jsapiTicket)) {
      account.setJsapiTicketExpiresTime(0L);
    } else {
      // 预留200秒的时间
      account
          .setJsapiTicketExpiresTime(System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l);
    }
    accountService.saveOrUpdate(account);
  }

  @Override
  public String getCardApiTicket() {
    return ensureAccount().getCardApiTicket();
  }

  @Override
  public boolean isCardApiTicketExpired() {
    final WxAccountEntity account = ensureAccount();
    long expiresTime = (account.getCardApiTicketExpiresTime() == null
        || StringUtils.isBlank(account.getCardApiTicket())) ? 0
            : account.getCardApiTicketExpiresTime();
    return System.currentTimeMillis() > expiresTime;
  }

  @Override
  public void expireCardApiTicket() {
    final WxAccountEntity account = ensureAccount();
    account.setCardApiTicketExpiresTime(0L);
    accountService.saveOrUpdate(account);
  }

  @Override
  public void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) {
    final WxAccountEntity account = ensureAccount();
    account.setCardApiTicket(cardApiTicket);
    if (StringUtils.isBlank(cardApiTicket)) {
      account.setCardApiTicketExpiresTime(0L);
    } else {
      account.setCardApiTicketExpiresTime(
          System.currentTimeMillis() + (expiresInSeconds - 200) * 1000l);
    }
    accountService.saveOrUpdate(account);
  }

  @Override
  public String getAppId() {
    return ensureAccount().getAppid();
  }

  @Override
  public String getSecret() {
    return ensureAccount().getAppsecret();
  }

  @Override
  public String getToken() {
    return token;
  }

  @Override
  public String getAesKey() {
    return ensureAccount().getAesKey();
  }

  @Override
  public long getExpiresTime() {
    return ensureAccount().getExpiresTime();
  }

  @Override
  public String getOauth2redirectUri() {
    return ensureAccount().getOauth2redirectUri();
  }

  @Override
  public String getHttpProxyHost() {
    return null;
  }

  @Override
  public int getHttpProxyPort() {
    return 0;
  }

  @Override
  public String getHttpProxyUsername() {
    return null;
  }

  @Override
  public String getHttpProxyPassword() {
    return null;
  }

  @Override
  public File getTmpDirFile() {
    return null;
  }

  @Override
  public ApacheHttpClientBuilder getApacheHttpClientBuilder() {
    return null;
  }

  @Override
  public Lock getAccessTokenLock() {
    return accessTokenLock;
  }

  @Override
  public Lock getJsapiTicketLock() {
    return jsapiTicketLock;
  }

  @Override
  public Lock getCardApiTicketLock() {
    return cardApiTicketLock;
  }

  @Override
  public boolean autoRefreshToken() {
    return true;
  }

}
